package com.credithc.signature.common.service;

import cfca.seal.bean.SealInfoBean;
import cfca.seal.servlet.SealClient;
import cfca.seal.util.StrategyUtil;
import cfca.seal.util.StringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.credithc.baseserv.pageHelper.PageInfo;
import com.credithc.signature.common.constant.CacheConstant;
import com.credithc.signature.common.constant.ManagerConstant;
import com.credithc.signature.common.constant.SealConstant;
import com.credithc.signature.common.mapper.ChannelMapper;
import com.credithc.signature.common.mapper.FddSealInfoMapper;
import com.credithc.signature.common.mapper.OfficialSealTemplateMapper;
import com.credithc.signature.common.mapper.ProductSignMapper;
import com.credithc.signature.common.mapper.SealChannelMapper;
import com.credithc.signature.common.mapper.SealInfoMapper;
import com.credithc.signature.common.mapper.TemplateMapper;
import com.credithc.signature.common.po.Channel;
import com.credithc.signature.common.po.Dictionary;
import com.credithc.signature.common.po.FddConfig;
import com.credithc.signature.common.po.FddSealInfo;
import com.credithc.signature.common.po.OfficialSealTemplate;
import com.credithc.signature.common.po.SealChannel;
import com.credithc.signature.common.po.SealInfo;
import com.credithc.signature.common.po.Template;
import com.credithc.signature.common.ro.SealInfoReplenishRo;
import com.credithc.signature.common.ro.manager.SealInfoRo;
import com.credithc.signature.common.service.lanmao.LanmaoSignImageService;
import com.credithc.signature.common.utils.CacheUtil;
import com.credithc.signature.common.utils.ErrorCodeHelper;
import com.credithc.signature.common.utils.FddConfigMap;
import com.credithc.signature.common.utils.ManagerBeanUtil;
import com.credithc.signature.common.utils.PageUtils;
import com.credithc.signature.common.vo.manager.DictionaryVo;
import com.credithc.signature.common.vo.manager.SealInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SealInfoService {

    @Autowired
    SealInfoMapper sealInfoMapper;

    @Autowired
    FddSealInfoMapper fddSealInfoMapper;

    @Autowired
    DictionaryService dictionaryService;

    @Autowired
    SealChannelMapper sealChannelMapper;

    @Autowired
    ProductSignMapper productSignMapper;


    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRED)
    public int insert(SealInfo sealInfo) {
        return sealInfoMapper.insert(sealInfo);
    }

    public int insertSelective(SealInfo sealInfo) {
        return sealInfoMapper.insertSelective(sealInfo);
    }

    public int insertList(List<SealInfo> sealInfos) {
        return sealInfoMapper.insertList(sealInfos);
    }

    public int updateByPrimaryKeySelective(SealInfo sealInfo) {
        return sealInfoMapper.updateByPrimaryKeySelective(sealInfo);
    }

    public SealInfo selectByIdNoAndSealName(String idNo, String sealName) {
        return sealInfoMapper.selectByIdNoAndSealName(idNo, sealName);
    }

    public List<SealInfo> selectByIdNoList(List idNoList) {
        return sealInfoMapper.selectByIdNoList(idNoList);
    }

    public List<SealInfo> selectBySealCodeList(List sealCodeList) {
        return sealInfoMapper.selectBySealCodeList(sealCodeList);
    }

    public SealInfo selectBySealCode(String sealCode) {
        return sealInfoMapper.selectBySealCode(sealCode);
    }

    //-----------------------------------主方法-----------------------------------

    /**
     * 查询所有
     *
     * @param sealInfoRo
     * @return
     */
    public PageInfo<SealInfoVo> queryAll(SealInfoRo sealInfoRo) {
        try {
            //租户管理员查询
            if (StringUtils.isNotEmpty(sealInfoRo.getChannelNo())) {
                log.info("查询所有印章req=" + JSON.toJSONString(sealInfoRo));
                PageUtils.setPageNo(sealInfoRo);
                return queryAllByChannel(sealInfoRo);
            } else {
                return new PageInfo<>(null, 0, sealInfoRo.getPageNo(), sealInfoRo.getPageSize());
            }
        } catch (Exception e) {
            log.error("查询所有公章发生异常", e);
        }
        return null;
    }

    /**
     * 查询中金、法大大渠道公章
     *
     * @param sealInfoRo
     * @return
     */
    public PageInfo<SealInfoVo> queryAllByChannel(SealInfoRo sealInfoRo) throws Exception {
        // 根据渠道配置的三方查询对应的公章信息
        String channelNo = sealInfoRo.getChannelNo();
        FddConfig fddConfig = FddConfigMap.getConfig().get(channelNo);
        if (fddConfig != null) {
            List<FddSealInfo> infoList = fddSealInfoMapper.listByParamsAndPage(sealInfoRo);
            int count = fddSealInfoMapper.countByParamsAndPage(sealInfoRo);
            List<SealInfoVo> vos = buildVos2(infoList);
            return new PageInfo<>(vos, count, sealInfoRo.getPageNo(), sealInfoRo.getPageSize());
        } else {
            List<SealInfo> infoList = sealInfoMapper.listByParamsAndPage(sealInfoRo);
            int count = sealInfoMapper.countByParamsAndPage(sealInfoRo);
            List<SealInfoVo> vos = buildVos(infoList);
            return new PageInfo<>(vos, count, sealInfoRo.getPageNo(), sealInfoRo.getPageSize());
        }
    }

    /**
     * 查询证件类型
     *
     * @return
     */
    public List<DictionaryVo> queryCertType() {
        List<Dictionary> dictionaryPos = dictionaryService.selectByTypeAndOther(ManagerConstant.CERT_TYPE, ManagerConstant.EXT1);
        List<DictionaryVo> list = new ArrayList<>();
        dictionaryPos.forEach(po -> {
            DictionaryVo vo = new DictionaryVo();
            BeanUtils.copyProperties(po, vo);
            list.add(vo);
        });
        return list;
    }

    public List<DictionaryVo> queryCertTypeP() {
        List<Dictionary> dictionaryPos = dictionaryService.selectByTypeAndOther(ManagerConstant.CERT_TYPE, ManagerConstant.PERSON);
        List<DictionaryVo> list = new ArrayList<>();
        dictionaryPos.forEach(po -> {
            DictionaryVo vo = new DictionaryVo();
            BeanUtils.copyProperties(po, vo);
            list.add(vo);
        });
        return list;
    }

    /**
     * 修改状态
     *
     * @param sealInfoRo
     * @param channelNo
     */
    @Transactional(rollbackFor = RuntimeException.class, propagation = Propagation.REQUIRED)
    public void updateSts(SealInfoRo sealInfoRo, String channelNo) {
        SealChannel sealChannel = new SealChannel();
        sealChannel.setStatus(sealInfoRo.getStatus());
        Example example = new Example(SealChannel.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("sealCode", sealInfoRo.getSealCode());
        criteria.andEqualTo("channelNo", channelNo);
        sealChannelMapper.updateByExampleSelective(sealChannel, example);
    }

    /**
     * 查询单条--中金
     *
     * @param id
     * @return
     */
    public SealInfoVo queryOne(Long id) {
        SealInfo sealInfo = sealInfoMapper.selectByPrimaryKey(id);
        SealInfoVo sealInfoVo = new SealInfoVo();
        return convertPotoVo(sealInfo, sealInfoVo);
    }

    /**
     * 查询单条--法大大
     *
     * @param id
     * @return
     */
    public SealInfoVo queryOne2(Long id, String appId) {
        FddSealInfo sealInfo = fddSealInfoMapper.selectByPrimaryKey(id);
        SealInfoVo sealInfoVo = new SealInfoVo();
        SealInfo sealInfo1 = new SealInfo();
        BeanUtils.copyProperties(sealInfo, sealInfo1);
        return convertPotoVo(sealInfo1, sealInfoVo);
    }

    /**
     * 根据sealName查询
     *
     * @param sealName
     * @return
     */
    public SealInfo selectBySealName(String sealName) {
        SealInfo sealInfo = new SealInfo();
        sealInfo.setSealName(sealName);
        Map<String, Object> params = ManagerBeanUtil.buildQueryParams(sealInfo);
        return sealInfoMapper.selectOneByExample(params.get(ManagerConstant.EXAMPLE));
    }

    /**
     * 根据identificationNo查询
     *
     * @param identificationNo
     * @return
     */
    public SealInfo selectByIdentificationNo(String identificationNo) {
        SealInfo sealInfo = new SealInfo();
        sealInfo.setIdentificationNo(identificationNo);
        Map<String, Object> params = ManagerBeanUtil.buildQueryParams(sealInfo);
        return sealInfoMapper.selectOneByExample(params.get(ManagerConstant.EXAMPLE));
    }

    /**
     * 查询sealName
     *
     * @param sealInfoRo
     * @return
     */
    public JSONArray searchSealName(SealInfoRo sealInfoRo) {
        Example example = new Example(SealInfo.class);
        Example.Criteria criteria = example.createCriteria();
        if (StringUtils.isNotEmpty(sealInfoRo.getSealName())) {
            String sealName = sealInfoRo.getSealName();
            criteria.andLike("sealName", "%" + sealName.trim() + "%");
        }
        List<SealInfo> infos = sealInfoMapper.selectByExample(example);
        JSONArray array = new JSONArray();
        infos.forEach(po -> {
            JSONObject json = new JSONObject();
            json.put("sealName", po.getSealName());
            array.add(json);
        });
        return array;
    }


    //-----------------------------------工具方法-----------------------------------
    private List<SealInfoVo> buildVos(List<SealInfo> infoList) {
        List<SealInfoVo> list = new ArrayList<>();
        infoList.forEach(po -> {
            SealInfoVo infoVo = new SealInfoVo();
            list.add(convertPotoVo(po, infoVo));
        });
        return list;
    }

    private SealInfoVo convertPotoVo(SealInfo po, SealInfoVo infoVo) {
        BeanUtils.copyProperties(po, infoVo);
        //证件类型
        if (StringUtils.isNotEmpty(po.getIdentificationType())) {
            String name = dictionaryService.selectOneByTypeAndCode(ManagerConstant.CERT_TYPE, po.getIdentificationType());
            infoVo.setIdentificationTypeName(name);
        }
        //公章类型
        if (po.getOfficeSealType() != null) {
            String name = dictionaryService.selectOneByTypeAndCode(ManagerConstant.OFFICE_SEAL_TYPE, po.getOfficeSealType().toString());
            infoVo.setOfficeSealTypeName(name);
        }
        //公章来源
        if (po.getSealSource() != null) {
            String name = dictionaryService.selectOneByTypeAndCode(ManagerConstant.SEAL_SOURCE, po.getSealSource().toString());
            infoVo.setSealSourceName(name);
        }
        //印章状态
        if (po.getStatus() != null) {
            String name = dictionaryService.selectOneByTypeAndCode(ManagerConstant.COMMON_STATUS, po.getStatus().toString());
            infoVo.setStatusName(name);
        } else {
            infoVo.setStatusName(ManagerConstant.UNUSE);
        }
        return infoVo;
    }

    private List<SealInfoVo> buildVos2(List<FddSealInfo> infoList) {
        List<SealInfoVo> list = new ArrayList<>();
        infoList.forEach(po -> {
            SealInfoVo infoVo = new SealInfoVo();
            SealInfo sealInfo = new SealInfo();
            BeanUtils.copyProperties(po, sealInfo);
            list.add(convertPotoVo(sealInfo, infoVo));
        });
        return list;
    }

    /**
     * 做数据权限的控制，将集合与seal_channle表数据集合做交集
     *
     * @param infoList
     * @param channelNo
     * @return
     */
    private List<SealInfo> getSectionList(List<SealInfo> infoList, String channelNo) {
        if (StringUtils.isNotBlank(channelNo)) {
            Example example = new Example(SealChannel.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andEqualTo("channelNo", channelNo);
            List<SealChannel> sealChannels = sealChannelMapper.selectByExample(example);
            return infoList.stream().filter(info -> sectionWithSealList(info, sealChannels)).collect(Collectors.toList());
        }
        return infoList;
    }

    private boolean sectionWithSealList(SealInfo info, List<SealChannel> sealChannels) {
        AtomicBoolean result = new AtomicBoolean(false);
        sealChannels.forEach(sealChannel -> {
            if (info.getSealCode().equals(sealChannel.getSealCode())) {
                result.set(true);
            }
        });
        return result.get();
    }

    /**
     * 根据sealCode删除
     *
     * @param sealCode
     */
    @Transactional(rollbackFor = RuntimeException.class, propagation = Propagation.REQUIRED)
    public void deleteBySealCode(String sealCode) {
        try {
            SealInfo sealInfo = new SealInfo();
            sealInfo.setSealCode(sealCode);
            Map<String, Object> params = ManagerBeanUtil.buildQueryParams(sealInfo);
            sealInfoMapper.deleteByExample(params.get(ManagerConstant.EXAMPLE));
            log.info("删除SealInfo表公章信息成功......");
        } catch (Exception e) {
            log.error("删除SealInfo表公章信息失败......");
        }
    }

    /**
     * 查询该公章关键字是否存在
     *
     * @param keyWords
     * @return
     */
    public SealInfo selectBySealKeyWord(String keyWords) {
        SealInfo sealInfo = new SealInfo();
        sealInfo.setKeyWords(keyWords);
        Map<String, Object> params = ManagerBeanUtil.buildQueryParams(sealInfo);
        return sealInfoMapper.selectOneByExample(params.get(ManagerConstant.EXAMPLE));
    }

    @Autowired
    private OfficialSealTemplateMapper officialSealTemplateMapper;

    @Autowired
    private TemplateMapper templateMapper;

    @Autowired
    private ChannelMapper channelMapper;

    public boolean existSeal(String templateNo, String channelNo) {
        Example example = new Example(OfficialSealTemplate.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("templateNo", templateNo);
        List<OfficialSealTemplate> officialSealTemplates = officialSealTemplateMapper.selectByExample(example);
        List<String> sealCodes = new ArrayList<>();
        for (OfficialSealTemplate officialSealTemplate : officialSealTemplates) {
            sealCodes.add(officialSealTemplate.getOfficialSealCode());
        }
        Example example1 = new Example(SealChannel.class);
        Example.Criteria criteria1 = example1.createCriteria();
        criteria1.andEqualTo("channelNo", channelNo);
        if (!sealCodes.isEmpty()) {
            criteria1.andIn("sealCode", sealCodes);
        }
        List<SealChannel> sealChannels = sealChannelMapper.selectByExample(example1);
        if (sealChannels == null || sealChannels.size() <= 0) {
            return false;
        }
        for (SealChannel s : sealChannels) {
            if (s.getStatus() != 1) {
                return false;
            }
        }
        return true;
    }

    /**
     * 业务系统指定盖定公章验证公章有效性
     *
     * @param officialSealCodes
     * @param channelNo
     * @return
     */
    public boolean existSeal(List<String> officialSealCodes, String channelNo, String templateNo) {

        Example ostt = new Example(OfficialSealTemplate.class);
        Example.Criteria ostc = ostt.createCriteria();
        ostc.andEqualTo("templateNo", templateNo);
        List<OfficialSealTemplate> officialSealTemplates = officialSealTemplateMapper.selectByExample(ostt);

        //修补bug
        if (officialSealTemplates == null || officialSealTemplates.size() == 0) {
            List<Template> templates = templateMapper.selectByExample(ostt);
            if (!officialSealCodes.isEmpty()) {
                officialSealCodes.forEach(f -> {
                    OfficialSealTemplate officialSealTemplate = new OfficialSealTemplate();
                    officialSealTemplate.setOfficialSealCode(f);
                    officialSealTemplate.setTemplateNo(templates.get(0).getTemplateNo());
                    officialSealTemplates.add(officialSealTemplate);
                });
            }
        }
        //修补bug

        Map<String, OfficialSealTemplate> allSealCodes = new HashMap<>();
        for (OfficialSealTemplate officialSealTemplate : officialSealTemplates) {
            allSealCodes.put(officialSealTemplate.getOfficialSealCode(), officialSealTemplate);
        }
        List<SealInfo> sealInfos = new ArrayList<>();
        if (!officialSealCodes.isEmpty()) {
            Example example = new Example(SealInfo.class);
            Example.Criteria criteria = example.createCriteria();
            criteria.andIn("sealCode", officialSealCodes);
            sealInfos = sealInfoMapper.selectByExample(example);
            if (sealInfos.size() < 1) {
                Example example1 = new Example(FddSealInfo.class);
                Example.Criteria criteria1 = example1.createCriteria();
                criteria1.andIn("sealCode", officialSealCodes);
                List<FddSealInfo> fddSealInfos = fddSealInfoMapper.selectByExample(example1);
                for (FddSealInfo fddSealInfo : fddSealInfos) {
                    SealInfo sealInfo = new SealInfo();
                    BeanUtils.copyProperties(fddSealInfo, sealInfo);
                    sealInfos.add(sealInfo);
                }
            }
        } else {
            return true;
        }
        List<String> sealCodes = new ArrayList<>();
        for (SealInfo sealInfo : sealInfos) {
            OfficialSealTemplate officialSealTemplate = allSealCodes.get(sealInfo.getSealCode());
            if (officialSealTemplate == null) {
                return false;
            }
            sealCodes.add(sealInfo.getSealCode());
        }
        if (sealCodes.isEmpty()) {
            return false;
        }
        Example example1 = new Example(SealChannel.class);
        Example.Criteria criteria1 = example1.createCriteria();
        criteria1.andEqualTo("channelNo", channelNo);
        criteria1.andIn("sealCode", sealCodes);
        List<SealChannel> sealChannels = sealChannelMapper.selectByExample(example1);

        //修补bug
        if (sealChannels == null || sealChannels.size() == 0) {
            if (StringUtil.isNotEmpty(channelNo)) {
                Channel channel = channelMapper.selectByChannelNo(channelNo);
                Example example2 = new Example(SealChannel.class);
                Example.Criteria criteria2 = example2.createCriteria();
                criteria2.andEqualTo("channelNo", channel.getChannelNo());
                criteria2.andIn("sealCode", sealCodes);
                sealChannels = sealChannelMapper.selectByExample(example2);
            }
        }
        //修补bug

        if (sealChannels == null || sealChannels.size() < sealCodes.size()) {
            return false;
        }
        for (SealChannel s : sealChannels) {
            if (s.getStatus() != 1) {
                return false;
            }
        }
        return true;
    }

    /**
     * 更新印章图片
     *
     * @param sealInfoRo
     * @return
     */

    @Autowired
    private LanmaoSignImageService lanmaoSignImageService;


    public String updateSealImg(SealInfoRo sealInfoRo, SealClient client) throws Exception {
        //1.更新三方数据
        String sealOrg = sealInfoRo.getSealOrg();
        String sealName = sealInfoRo.getSealName();
        String sealCode = sealInfoRo.getSealCode();
        String sealPwd = sealInfoRo.getSealPwd();
        String imageCode = sealInfoRo.getImageCode();
        String sealImageSize = sealInfoRo.getSealImageSize();
        byte[] image = sealInfoRo.getImage();

        SealInfoBean sealInfoBean = new SealInfoBean(SealConstant.SEAL_PERSON, sealOrg, sealName, sealCode, sealPwd, SealConstant.SEAL_TYPE, imageCode, SealConstant.ORG_CODE, SealConstant.SEAL_FLAG);
        sealInfoBean.setSealImageSize(sealImageSize);
        String sealInfoXML = StrategyUtil.creatSealInfoXML(sealInfoBean);
        String result = client.updateSealAutomation(image, sealInfoXML);
//        String result = client.autoUpdateSeal(image, sealInfoXML);
        log.info("update image result = " + result);
        if (SealConstant.SUCCESS.equals(StringUtil.getNodeText(result, SealConstant.RETURNCODE))) {
            log.info("更新远程图片信息成功......");
            //2.更新本地数据
            updateSealImg(sealCode, image, sealImageSize);
            //更新懒猫公章图片
//            SealInfo sealInfo = sealInfoMapper.selectBySealCode(sealCode);
//            lanmaoSignImageService.updataSignImage(sealInfo);
            return "SUCCESS";
        } else {
            log.error("更新远程图片信息失败......");
            return ErrorCodeHelper.parseErrorCode(StringUtil.getNodeText(result, SealConstant.RETURNCODE), StringUtil.getNodeText(result, SealConstant.RETURNMSG));
        }
    }

    /**
     * 更新本地图片信息
     *
     * @param sealCode
     * @param sealImageSize
     */
    private void updateSealImg(String sealCode, byte[] image, String sealImageSize) {
        SealInfo sealInfo = new SealInfo();
        sealInfo.setImage(image);
        sealInfo.setExt2(sealImageSize);
        Example example = new Example(SealInfo.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("sealCode", sealCode);
        try {
            sealInfoMapper.updateByExampleSelective(sealInfo, example);
            log.info("更新本地图片信息成功......");
        } catch (Exception e) {
            log.info("更新本地图片信息失败......", e);
        }
    }

    public PageInfo<SealInfo> selectReplenish() {
        Example example = new Example(SealInfo.class);
        Example.Criteria criteria = example.createCriteria();
        example.selectProperties("id");
        example.selectProperties("sealCode");
        example.selectProperties("sealOrg");
        example.selectProperties("sealName");
        criteria.orIsNull("legalPersonName");
        criteria.orIsNull("legalPersonId");
        criteria.orIsNull("legalPersonCardType");
        criteria.orIsNull("phone");
        criteria.orIsNull("contactPhone");
        criteria.orNotEqualTo("identificationType", "N");
        PageInfo<SealInfo> pageInfo = new PageInfo<>();
        pageInfo.setList(sealInfoMapper.selectByExample(example));
        pageInfo.setTotalCount(sealInfoMapper.selectCountByExample(example));
        return pageInfo;


    }

    public SealInfo selectReplenishInfo(Long id) {
        Example example = new Example(SealInfo.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("id", id);
        SealInfo sealInfo = sealInfoMapper.selectOneByExample(example);
        if (!sealInfo.getIdentificationType().equals("N")) {
            sealInfo.setIdentificationType(null);
            sealInfo.setIdentificationNo(null);
        }
        return sealInfo;
    }

    public void replenishSave(SealInfoReplenishRo sealInfo) {
        if (StringUtils.isNotBlank(sealInfo.getPictureId())) {
            Example e = new Example(SealInfo.class);
            Example.Criteria c = e.createCriteria();
            c.andEqualTo("id", sealInfo.getId());
            SealInfo sealInfo1 = sealInfoMapper.selectOneByExample(e);
            if (StringUtils.isNotBlank(sealInfo1.getUserId())) {
                lanmaoSignImageService.updataSignImage(sealInfo1);
            }
        }
        sealInfo.setIdentificationType("N");
        Example example = new Example(SealInfo.class);
        Example.Criteria criteria = example.createCriteria();
        criteria.andEqualTo("id", sealInfo.getId());
        sealInfoMapper.updateByExampleSelective(sealInfo, example);

    }

    /**
     * 查询渠道公章信息
     *
     * @param channelNo
     * @return
     */
    public List<SealChannel> selectByChannelNo(String channelNo) {
        List<SealChannel> cacheSealChannels = null;
        try {
            cacheSealChannels = CacheUtil.getChannelSealLoadingCache().get(CacheConstant.CHANNEL_SEAL_PREFIX + channelNo);
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        return cacheSealChannels;
    }
}
